package com.sparrow.mvc;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sparrow.constant.*;
import com.sparrow.core.Log;
import com.sparrow.core.asm.MethodAccessor;
import com.sparrow.enums.OPERATION_RESULT;
import com.sparrow.ioc.BeanFactory;
import com.sparrow.support.ActionFilterSupport;
import com.sparrow.support.ActionSupport;
import com.sparrow.support.Privilege;
import com.sparrow.support.Login;
import com.sparrow.utils.Config;
import com.sparrow.utils.StringUtil;

public class ActionFilter4Method extends ActionFilterSupport implements Filter {
	private FilterConfig config;

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		String actionKey = super.getActionKey(httpRequest);
		request.setAttribute(CONFIG.ROOT_PATH, super.getBasePath(httpRequest));
		request.setAttribute(CONFIG.RESOURCE,
				Config.getValueInCache(CONFIG.RESOURCE));
		request.setAttribute(
				LANGUAGE_CONFIG_KEY.WEBSIT_NAME,
				Config.getValueInFile(LANGUAGE_CONFIG_KEY.WEBSIT_NAME,
						super.getSystemLanguage()));
		BeanFactory beanFactory = BeanFactory.getInstance();
		/*
		 * javax.servlet.include.request_uri javax.servlet.include.context_path
		 * javax.servlet.include.servlet_path javax.servlet.include.path_info
		 * javax.servlet.include.query_string
		 */

		ActionEntity actionEntity = null;
		String xmlName = config.getServletContext().getInitParameter(
				"mvc_config");
		try {
			actionEntity = ActionConfig.getActionConfig().getActionEntity(
					actionKey, xmlName);

			String userId = Login.getUser(httpRequest.getCookies());
			request.setAttribute(USER.ID, userId);
			request.setAttribute(USER.LOGIN_NAME,
					Login.getUser(httpRequest.getCookies(), true));

			if (httpRequest.getQueryString() != null) {
				request.setAttribute("hdnPreUrl.value",
						httpRequest.getQueryString());
			}
			if (actionEntity == null) {
				chain.doFilter(request, response);
			} else {
				// 表示需要登录
				if (actionEntity.getLoginType() != 0) {
					// 游客
					if (userId.equals(USER.VISITOR_ID)) {
						String loginUrl = super.getBasePath(httpRequest)
								+ (actionEntity.getLoginType() == 1 ? Config
										.getValueInCache(CONFIG.LOGIN_URL)
										: Config.getValueInCache(CONFIG.INNER_LOGIN_URL));
						if (!actionEntity.getIsAjax()) {
							StringBuffer redirectUrl = httpRequest
									.getRequestURL();
							if (httpRequest.getQueryString() != null) {
								redirectUrl.append("?"
										+ httpRequest.getQueryString());
							}
							loginUrl = loginUrl + "?" + redirectUrl.toString();
							httpResponse.sendRedirect(loginUrl);
						} else {
							response.getWriter().write("nologin:" + loginUrl);
						}
						return;
					} else {
						if (actionEntity.getIsValidPrivilege()) {
							Privilege sprivilege = BeanFactory.getInstance()
									.getBean(SYS_OBJECT_NAME.PRIVILEGE_SERVER);

							String forumCode = request
									.getParameter("forumCode");

							if (!sprivilege.isAccessable(
									super.getCurrentUserId(httpRequest),
									actionKey, forumCode)) {
								response.getWriter()
										.write(COMMON.ACCESS_DENIED);
								return;
							}
						}
					}
				}

				// 初始化action对象并注所有依赖对象
				ActionSupport actionInstance = beanFactory.getBean(actionEntity
						.getActionName());
				actionInstance.setRequest(httpRequest);
				actionInstance.setResponse(httpResponse);

				Method acitonMethod = actionEntity.getMethod();
				System.out.println("actionFilter:" + actionKey + actionInstance
						+ "|" + acitonMethod);
				Object[] args = this.actionIoc(request, actionEntity);
				String actionReturnValue = super.STOP;
				if (acitonMethod.getReturnType().equals(String.class)) {
					actionReturnValue = acitonMethod.invoke(actionInstance)
							.toString();
				} else {
					acitonMethod.invoke(actionInstance, args);
				}
				if (!actionEntity.getIsAjax()) {
					if (actionKey.endsWith(".jsp")) {
						chain.doFilter(request, response);
					} else if (actionReturnValue.equals(super.STOP)) {
						return;
					} else if (actionReturnValue.equals(super.SOURCE)) {
						String sourceUrl = actionEntity.getSourceUrl();
						if (request.getAttribute(super.SOURCEURL) != null) {
							sourceUrl = request.getAttribute(super.SOURCEURL)
									.toString();
						}
						RequestDispatcher dispatcher = this.getServletContent()
								.getRequestDispatcher(sourceUrl);
						dispatcher.forward(request, response);
					} else {
						String directUrl = actionEntity.getDirectionUrl();
						if (request.getAttribute(super.DIRECTIONURL) != null) {
							directUrl = request
									.getAttribute(super.DIRECTIONURL)
									.toString();
						}
						Object urlParameters = request
								.getAttribute(super.URLPARAMETERS);
						if (urlParameters != null) {
							@SuppressWarnings("unchecked")
							List<String> listParameters = (List<String>) urlParameters;
							for (int i = 0; i < listParameters.size(); i++) {
								if (listParameters.get(i) != null) {
									directUrl = directUrl
											.replace("$", "&")
											.replace("$", "&")
											.replace("{" + i + "}",
													listParameters.get(i));
								}
							}
						}
						if (!directUrl.startsWith("http://")) {
							directUrl = Config
									.getValueInCache(CONFIG.ROOT_PATH)
									+ directUrl;
						}
						httpResponse.sendRedirect(directUrl);
					}
				} else {
					if (request.getAttribute(super.AJAXCACHE) == null) {
						response.getWriter().write(
								OPERATION_RESULT.OK.toString());
					} else {
						response.getWriter().write(
								request.getAttribute(super.AJAXCACHE)
										.toString());
					}
				}
			}

			if (actionKey.endsWith(".jsp")) {
				if (request.getAttribute(actionKey) != null) {
					response.getWriter().write(
							request.getAttribute(actionKey).toString());
				}
			}
		} catch (Exception e) {
			Log.getInstance().error(e.getCause());
			if (actionEntity != null && actionEntity.getIsAjax()) {
				String errorInfo = Config.getValueInFile(
						LANGUAGE_CONFIG_KEY.ERROR_MSG,
						super.getSystemLanguage());
				response.getWriter().write("error|" + errorInfo);

			} else {
				RequestDispatcher dispatcher = this.getServletContent()
						.getRequestDispatcher(
								Config.getValueInCache(CONFIG.ERROR_URL));
				dispatcher.forward(request, response);
			}
		}
	}

	public void init(FilterConfig config) throws ServletException {
		this.config = config;
	}

	public ServletContext getServletContent() {
		return this.getConfig().getServletContext();
	}

	public FilterConfig getConfig() {
		return config;
	}

	public void setConfig(FilterConfig config) {
		this.config = config;
	}

	private Object[] actionIoc(ServletRequest request, ActionEntity actionEntity) {
		// 参数名称列表
		List<String> parameterList = actionEntity.getParameterNameList();
		Class<?>[] parameterClass = actionEntity.getMethod()
				.getParameterTypes();
		BeanFactory beanFactory = BeanFactory.getInstance();
		// 参数列表
		Object[] args = new Object[parameterList.size()];
		for (int i = 0; i < parameterList.size(); i++) {
			String parameterName = parameterList.get(i);
			// 如果是基本数据类型
			if (parameterClass[i].equals(String.class)) {
				args[i] = request.getParameter(parameterName);
			} else {
				Object entity = null;
				try {
					entity = parameterClass[i].newInstance();
				} catch (Exception e) {
					Log.getInstance().error(e);
					return null;
				}
				MethodAccessor methodAccessor = beanFactory
						.getProxyBean(parameterClass[i].getSimpleName());
				Method[] methods = parameterClass[i].getMethods();
				for (Method method : methods) {
					if (method.getName().startsWith("set")) {
						String parameterName4Request = parameterName
								+ "."
								+ StringUtil.setFirstByteLowerCase(method
										.getName().substring(3));
						methodAccessor.set(entity, method.getName(),
								request.getParameter(parameterName4Request));
					}
				}
				args[i] = entity;
			}
		}
		return args;
	}
}
